package com.selebash.features;

import com.selebash.config.Config;
import com.selebash.ParserContext;
import com.selebash.annotation.Feature;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * @author sad
 */
public class FeatureInitProcessor {

    public void process(ParserContext parserContext, Config config) {
        List<Class> classes = config.getFeaturesClasses();
        for (Class clazz : classes) {
            List<FeatureHolder> fh = processClass(clazz, config.getFeatureFactory());
            parserContext.getFeatures().addAll(fh);
        }
    }

    public List<Method> getFeatureMethodsInClass(Class clazz) {
        List<Method> result = new ArrayList<>();
        while (clazz != null) {
            for (Method m : clazz.getDeclaredMethods()) {
                if (m.isAnnotationPresent(Feature.class)) {
                    result.add(m);
                }
            }

            clazz = clazz.getSuperclass();
        }

        return result;
    }

    public List<FeatureHolder> processClass(Class clazz, FeatureFactory featureFactory) {
        List<FeatureHolder> result = new ArrayList<>();
        List<Method> featureMethods = getFeatureMethodsInClass(clazz);
        Object featureOwner = featureFactory.create(clazz);
        for (Method featureMethod : featureMethods) {
            FeatureHolder fh = new FeatureHolder();
            fh.setObjectFeatureOwner(featureOwner);
            featureMethod.setAccessible(true);
            fh.setMethod(featureMethod);
            Feature annotation=featureMethod.getAnnotation(Feature.class);
            fh.setHasNested(annotation.hasNested());
            fh.setPattern(createPattern(annotation));
            result.add(fh);
        }

        return result;
    }

    private Pattern createPattern(Feature feature) {
        int flag = Pattern.UNICODE_CASE;
        flag = flag | Pattern.UNICODE_CHARACTER_CLASS;
        if (!feature.caseSensitive()) {
            flag = flag | Pattern.CASE_INSENSITIVE;
        }

        Pattern pattern = Pattern.compile(feature.value(), flag);
        return pattern;
    }
}
